package com.marktotop.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


/**
 * RedisConfig 固定模板，开发直接使用
 *
 * @author WXLD
 * @Data 2021/6/20
 * @Since 1.0
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
        // 开发一般直接使用 <String, Object>
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 注入连接工厂
        redisTemplate.setConnectionFactory(factory);

        // Json序列化配置
        /**
         * DefaultTyping有四个选项：
         *      JAVA_LANG_OBJECT: 当对象属性类型为Object时生效；
         *      OBJECT_AND_NON_CONCRETE: 当对象属性类型为Object或者非具体类型（抽象类和接口）时生效；
         *      NON_CONCRETE_AND+_ARRAYS: 同上, 另外所有的数组元素的类型都是非具体类型或者对象类型；
         *      NON_FINAL: 对所有非final类型或者非final类型元素的数组。
         *
         * 因此，当开启DefaultTyping后，会开发者在反序列化时指定要还原的类，过程中调用其构造方法setter方法或某些特殊的getter方法，
         * 当这些方法中存在一些危险操作时就造成了代码执行。
         *
         */
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        jackson2JsonRedisSerializer.setObjectMapper(mapper);

        // key序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // value序列化
//        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // hash类型  key序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        // hash类型  value序列化
//        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        return redisTemplate;
    }

}
